package br.mcaslib.swiz.controller
{
	import br.mcaslib.collections.ListRemoteView;
	import br.mcaslib.collections.ListRemoteViewEvent;
	import br.mcaslib.common.FilterEngine;
	import br.mcaslib.swiz.event.CrudEvent;
	import br.mcaslib.swiz.event.FeedbackEvent;
	
	import mx.charts.chartClasses.InstanceCache;
	import mx.collections.ArrayCollection;
	import mx.rpc.AsyncToken;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;
	
	/**
	 * crudService:
	 * 	save
	 * 
	 * crudTokenId
	 */
	public class CrudController extends BaseController
	{
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------

		public function CrudController() {
			trace( "CrudController: constructor" );
		}

		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------

		[Bindable]
		public var crudService:RemoteObject;

		[Bindable]
		public var collection:ListRemoteView;

		/** 
		 * Turn on/off tokenId process
		 */
		public var workWithTokenId:Boolean = true;
		
		//----------------------------------
		//  crudTokenId
		//----------------------------------

		/**
		 * Setup tokenId for this controller.
		 * Only events with this tokenId will be concerned for this controler
		 */
		public function set crudTokenId( value:String ):void {
			if( workWithTokenId && this._crudTokenId == null ) {
				this._crudTokenId = value;
				trace( 'CrudController: ' + this + ' - get token id "' + value + '"' );
			} else {
				trace( 'CrudController: ' + this + ' - current token id: ' + this._crudTokenId + ' discard message token id "' + value + '"' );
			}
		}
		
		public function get crudTokenId():String {
			return this._crudTokenId;
		}
		
		private var _crudTokenId:String = null;
		
		//--------------------------------------------------------------------------
		//
		//  Handler methods
		//
		//--------------------------------------------------------------------------
		
		[EventHandler(event='CrudEvent.EVENT_CRUD_SET_TOKEN')]
		public function setTokenHandler( event:CrudEvent ):void {
			this.crudTokenId = event.crudTokenId;
			event.stopImmediatePropagation();
		}
		
		[EventHandler(event='CrudEvent.EVENT_CRUD_SERVER_SAVE',properties='vo,crudTokenId')]
		public function saveHandler( vo:Object, crudTokenId:String ):AsyncToken {
			if( ! this.isEventForThisControler( crudTokenId ) ) return null;
			return this.executeServiceCall( crudService.save(vo), saveResultHandler, [crudTokenId] );
		}
		
		[EventHandler(event='CrudEvent.EVENT_CRUD_SERVER_LOAD',properties='crudTokenId,filterApply')]
		public function loadHandler( crudTokenId:String, filterApply:Array  ):AsyncToken {
			if( ! this.isEventForThisControler( crudTokenId ) ) return null;
			if( filterApply ) {
				if( filterApply.length > 0 ) {
					var args:Array = new Array();
					args.push( filterApply );
					this.collection.arguments = args;
				} else {
					this.collection.arguments = null;
				}
			}
			this.collection.addEventListener( ListRemoteViewEvent.LOADED_PAGE, listRemoteViewLoadedPageHandler );
			return this.collection.refresh();
		}
		
		[EventHandler(event='CrudEvent.EVENT_CRUD_SERVER_LOAD_FILTER',properties='crudTokenId')]
		public function loadFilterHandler( crudTokenId:String ):AsyncToken {
			if( ! this.isEventForThisControler( crudTokenId ) ) return null;
			trace( 'CrudContainer: EVENT_CRUD_SERVER_LOAD_FILTER - tokenId: ' + this.crudTokenId );
			return this.executeServiceCall( crudService.load_filter(), loadFilterResultHandler, [crudTokenId] );
		}
		
		public function saveResultHandler( event:ResultEvent, crudTokenId:String ):void {
			if( ! event.result ) {
				FeedbackEvent.createEvent( "O servidor enviou uma resposta não esperada. Por favor, clique no atualiza e verifique se a operação foi realizada." ).show(this);
				return;
			}
			
			if( event.result.hasOwnProperty( 'FORMERROR' ) || (! event.result) ) {
			  	FeedbackEvent.createEvent( "O servidor encontrou erros no preenchimento de alguns campos" ).show(this);
				return;
			}
			
			if( event.result && event.result.hasOwnProperty('id' ) ) {
				// Popula o collection com a recente alteracao
				// Pode ser um novo registro para acrescentar ou atualizar um registro existente
				// A busca deve ser sempre realizado pelo id do objeto porque podemos ter duas
				// instancia diferentes para o mesmo objeto - uma criado pelo servidor e outra
				// ja existente no collection
				var result:Object = event.result;
				var itemCollection:Object = this.collection.findItem( compareById, result );
				if( itemCollection ) {
					var indexItemCollection:int = this.collection.getItemIndex( itemCollection );
					this.collection.setItemAt( result, indexItemCollection );
				} else {
					this.collection.addItemAt( result, 0 );
				}
				
				FeedbackEvent.createEvent( "A operação foi realizada com sucesso no servidor" ).show(this);
				
				var eventSaveComplete:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_SAVE_COMPLETE );
				eventSaveComplete.crudTokenId = crudTokenId
				eventSaveComplete.vo = result;
				eventSaveComplete.itemSaved = result;
				this.dispatcher.dispatchEvent( eventSaveComplete );
			
			} else {
				FeedbackEvent.createEvent( "O servidor não respondeu corretamente. Por favor, faça um refresh e verifique se a ação foi realizado com sucesso" ).show(this);
				return;
				
			}
		}
		
		public function loadFilterResultHandler( event:ResultEvent, crudTokenId:String ):void {
			if( event.result ) {
				if( event.result is FilterEngine ) {
					var e:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD_FILTER_COMPLETE, this.crudTokenId );
					e.filterEngine = event.result as FilterEngine;
					this.dispatcher.dispatchEvent( e );
				} else {
					FeedbackEvent.createEvent( "O servidor não está suportando a realização de filtros (estrutura incompativel)" ).show(this);
				}
			}
		}
		
		public function listRemoteViewLoadedPageHandler( event:ListRemoteViewEvent ):void {
			this.collection.removeEventListener( ListRemoteViewEvent.LOADED_PAGE, listRemoteViewLoadedPageHandler );
			var e:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD_COMPLETE, this.crudTokenId );
			this.dispatcher.dispatchEvent( e );
		}
		
		//--------------------------------------------------------------------------
		//
		//  Protected/Private methods
		//
		//--------------------------------------------------------------------------
		
		protected function compareById( o1:Object, o2:Object ):Boolean {
			if( o1.hasOwnProperty( 'id' ) && o2.hasOwnProperty( 'id' ) ) {
				if( o1['id'] == o2['id'] ) {
					return true;
				}
			}
			return false;
		}
		
		/**
		 * Se tiver tokenId configurado, o controller so pode responder
		 * eventos com tokenId igual ao desse controller. Caso nao tenha 
		 * tokenId, o controller responde todos os eventos.
		 * 
		 * Se o flag de tokenId estiver desligado 'workWithTokenId' o controller
		 * deve responder todos os eventos independente de ter tokenId configurado
		 * ou não.
		 */
		protected function isEventForThisControler( crudTokenId:String ): Boolean {
			var result:Boolean = false;
			if( this.workWithTokenId ) {
				if( this.crudTokenId == crudTokenId ) {
					result = true;
				}
			} else {
				result = true;
			}
			if( crudTokenId == null ) {
				result = true;
			}
			return result;
		}
	}
}
